/*
 / _____)             _              | |
( (____  _____ ____ _| |_ _____  ____| |__
 \____ \| ___ |    (_   _) ___ |/ ___)  _ \
 _____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
    (C)2013 Semtech

Description: Board ADC driver implementation

License: Revised BSD License, see LICENSE.TXT file include in the project

Maintainer: Miguel Luis and Gregory Cristian
*/
#include "board.h"
#include "adc-board.h"

void AdcMcuInit(Adc_t *obj, PinNames adcInput)
{
    obj->Adc.Instance = (ADC_TypeDef *)ADC1_BASE;
    GpioInit(&obj->AdcInput, adcInput, PIN_ANALOGIC, PIN_PUSH_PULL, PIN_NO_PULL, 0);
}

void AdcMcuFormat(Adc_t *obj)
{
    ADC_HandleTypeDef *adc;

    __HAL_RCC_ADC1_CLK_ENABLE();

    obj->Adc.Init.OversamplingMode      = DISABLE;

    obj->Adc.Init.ClockPrescaler        = ADC_CLOCK_ASYNC_DIV8;
    obj->Adc.Init.LowPowerAutoPowerOff  = DISABLE;
    obj->Adc.Init.LowPowerFrequencyMode = ENABLE;
    obj->Adc.Init.LowPowerAutoWait      = DISABLE;

    obj->Adc.Init.Resolution            = ADC_RESOLUTION_12B;
    obj->Adc.Init.SamplingTime          = ADC_SAMPLETIME_7CYCLES_5;
    obj->Adc.Init.ScanConvMode          = ADC_SCAN_DIRECTION_FORWARD;
    obj->Adc.Init.DataAlign             = ADC_DATAALIGN_RIGHT;
    obj->Adc.Init.ContinuousConvMode    = ENABLE;
    obj->Adc.Init.DiscontinuousConvMode = DISABLE;
    obj->Adc.Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_NONE;
    obj->Adc.Init.EOCSelection          = ADC_EOC_SINGLE_CONV;
    obj->Adc.Init.DMAContinuousRequests = DISABLE;

    adc = &obj->Adc;
    HAL_ADC_Init(adc);
}

uint16_t AdcMcuRead(Adc_t *obj, uint32_t channel)
{
    ADC_HandleTypeDef *hadc;
    ADC_ChannelConfTypeDef adcConf;
    uint8_t read_cnt=0;
    __IO uint32_t adcData = 0;

    hadc = &obj->Adc;

    HAL_ADCEx_Calibration_Start(hadc, ADC_SINGLE_ENDED);

    adcConf.Channel = channel;

    HAL_ADC_ConfigChannel(hadc, &adcConf);

    /* Start ADC1 Software Conversion */
    HAL_ADC_Start(hadc);

    while (1)
    {
        HAL_ADC_PollForConversion(hadc, HAL_MAX_DELAY);

        /* Check if the continous conversion of regular channel is finished */
        if ((HAL_ADC_GetState(hadc) & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC)
        {

            /* Read a few times to make sure the data is stable */
            adcData = HAL_ADC_GetValue(hadc);
            read_cnt++;
            if(read_cnt == 7)
                break;
        }
    }

    HAL_ADC_DeInit(hadc);

    AdcDeInit(obj);

    __HAL_RCC_ADC1_CLK_DISABLE();

    return adcData;
}
